package com.yhxd.modular.reference.service;

import com.querydsl.core.QueryResults;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.yhxd.modular.news.service.UploadService;
import com.yhxd.modular.reference.dao.DirectoryDao;
import com.yhxd.modular.reference.dao.PublicFileDao;
import com.yhxd.modular.reference.entity.Directory;
import com.yhxd.modular.reference.entity.PublicFile;
import com.yhxd.modular.reference.entity.QPublicFile;
import com.yhxd.modular.system.entity.Config;
import com.yhxd.modular.system.entity.User;
import com.yhxd.utils.DateUtils;
import com.yhxd.utils.QueryDslUtils;
import com.yhxd.utils.RedissonUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.querydsl.QPageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.Map;

@Service
public class PublicFileService {

    @Autowired
    private JPAQueryFactory factory;

    @Autowired
    private PublicFileDao publicFileDao;

    @Autowired
    private DirectoryDao directoryDao;

    @Autowired
    private UploadService uploadService;

    public Page<PublicFile> findAll(QPageRequest pageRequest, Long dirId, String fileName, String createName, String createTime) {
        QPublicFile qPublicFile = QPublicFile.publicFile;

        Predicate where = qPublicFile.id.isNotNull();
        if (ObjectUtils.isNotEmpty(dirId)) {
            where = ExpressionUtils.and(where, qPublicFile.dirId.eq(dirId));
        }
        if (ObjectUtils.isNotEmpty(fileName)) {
            where = ExpressionUtils.and(where, qPublicFile.fileName.like("%" + fileName + "%"));
        }
        if (ObjectUtils.isNotEmpty(createName)) {
            where = ExpressionUtils.and(where, qPublicFile.createName.like("%" + createName + "%"));
        }
        if (ObjectUtils.isNotEmpty(createTime)) {
            Predicate createTimePredicate = qPublicFile.createTime.between(DateUtils.getTimesStart(createTime), DateUtils.getTimesEnd(createTime));
            where = ExpressionUtils.and(where, createTimePredicate);
        }
        QueryResults<PublicFile> publicFileList = this.factory
                .selectFrom(qPublicFile)
                .where(where)
                .orderBy(QueryDslUtils.getOrderSpecifier(pageRequest.getSort()))
                .offset(pageRequest.getOffset())
                .limit(pageRequest.getPageSize())
                .fetchResults();
        Page<PublicFile> publicFilePage = new PageImpl<>(publicFileList.getResults(), pageRequest, publicFileList.getTotal());
        return publicFilePage;
    }

    /**
     * 修改备注
     * @param id
     * @param note
     */
    @Transactional(rollbackFor = Exception.class)
    public void editNote(Long id, String note) {
        User shiroUser = (User) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal();
        PublicFile publicFile = this.publicFileDao.findById(id).orElse(null);
        if (null != publicFile) {
            QPublicFile qPublicFile = QPublicFile.publicFile;
            this.factory
                    .update(qPublicFile)
                    .set(qPublicFile.note, note)
                    .set(qPublicFile.updateName, shiroUser.getRealName())
                    .where(qPublicFile.id.eq(id))
                    .execute();
        }
    }

    /**
     * 删除文件
     * @param id
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) throws Exception {
        PublicFile publicFile = this.publicFileDao.findById(id).orElse(null);
        QPublicFile qPublicFile = QPublicFile.publicFile;
        this.factory
                .delete(qPublicFile)
                .where(qPublicFile.id.eq(id))
                .execute();

        Map<String, Config> configMap = (Map<String, Config>) RedissonUtils.getObject("config");
        String basePath = configMap.get("upload_mng").getConfValue();
        String filePath = (basePath + publicFile.getPath() + publicFile.getFileName() + "." + publicFile.getSuffix()).replaceAll("//", "/");
        try {
            FileUtils.forceDelete(new File(filePath));
        } catch (Exception e) {
            if (e instanceof FileNotFoundException) {

            } else {
                e.printStackTrace();
            }
        }
    }

    /**
     * 按id查询
     * @param id
     * @return
     */
    public PublicFile findById(Long id) {
        return this.publicFileDao.findById(id).orElse(null);
    }

    public String upload(HttpServletRequest request) throws Exception {
        User shiroUser = (User) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal();
        Map<String, Config> configMap = (Map<String, Config>) RedissonUtils.getObject("config");
        String basePath = configMap.get("upload_mng").getConfValue().replaceAll(",", "|");

        String url = null;
        Long dirId = Long.parseLong(request.getParameter("dirId"));
        Directory directory = this.directoryDao.findById(dirId).orElse(null);
        String dirPath = (directory.getDirPath() + directory.getDirName() + "/").replaceAll("//", "/");
        String filePath = basePath + dirPath;
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile file = multipartRequest.getFile(multipartRequest.getFileNames().next());
        String fileName = file.getOriginalFilename();
        if (0 != fileName.indexOf("\\\\")) {
            fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
        }
        String name = fileName.substring(0, fileName.lastIndexOf("."));
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
        Long fileSize = file.getSize();

        List<PublicFile> publicFileList = this.publicFileDao.findByDirIdAndFileNameAndSuffix(dirId, fileName, suffix);
        if (CollectionUtils.isEmpty(publicFileList)) {
            PublicFile publicFile = new PublicFile();
            publicFile.setPath(dirPath);
            publicFile.setFileName(name);
            publicFile.setNewFileName(name);
            publicFile.setSuffix(suffix);
            publicFile.setFileSize(fileSize);
            publicFile.setCreateName(shiroUser.getRealName());
            publicFile.setUpdateName(shiroUser.getRealName());
            publicFile.setDirectory(directory);
            this.publicFileDao.save(publicFile);

            url = uploadService.uploadFiles(multipartRequest, filePath);
        } else {
            throw new Exception("该目录下已存在同名文件");
        }
        return url;
    }
}
